package study.springcloud.gateway.filter.gateway;

import cn.hutool.core.collection.CollectionUtil;
import cn.hutool.core.util.StrUtil;
import cn.hutool.json.JSONUtil;
import lombok.Data;
import lombok.extern.slf4j.Slf4j;
import org.springframework.cloud.gateway.filter.GatewayFilter;
import org.springframework.cloud.gateway.filter.GatewayFilterChain;
import org.springframework.cloud.gateway.filter.factory.AbstractGatewayFilterFactory;
import org.springframework.http.server.reactive.ServerHttpRequest;
import org.springframework.stereotype.Component;
import org.springframework.web.server.ServerWebExchange;
import reactor.core.publisher.Mono;
import study.eggs.result.Results;
import study.springcloud.gateway.service.auth.AuthFactory;
import study.springcloud.gateway.service.auth.AuthService;
import study.springcloud.gateway.support.utils.RouteUtils;
import study.springcloud.gateway.support.utils.WebUtils;
import study.springcloud.gateway.support.utils.WriteUtils;

import java.util.Arrays;
import java.util.List;

@Slf4j
@Component
public class AuthGatewayFilterFactory extends AbstractGatewayFilterFactory<AuthGatewayFilterFactory.MyConfig> {

    public AuthGatewayFilterFactory() {
        super(MyConfig.class);
    }

    @Override
    public List<String> shortcutFieldOrder() {
        return Arrays.asList("type", "ignoreUris");
    }

    @Override
    public GatewayFilter apply(MyConfig myConfig) {
        return new MyGatewayFilter(myConfig);
    }

    /**
     * （★）网关过滤器
     */
    public class MyGatewayFilter implements GatewayFilter {

        private MyConfig myConfig;

        private MyGatewayFilter(MyConfig myConfig) {
            // 这里需要将自定义的 MyConfig 传过去，否则会报告 ClassCastException
            this.myConfig = myConfig;
        }

        @Override
        public Mono<Void> filter(ServerWebExchange exchange, GatewayFilterChain chain) {
            log.info(">>>>>>>>>> auth GatewayFilter, order= {}", 1);

            //step-1: ignore uri
            List<String> ignoreLt = myConfig.getIgnoreUris();
            String path = RouteUtils.getOriginalRequestURI(exchange).getPath();
            if (CollectionUtil.contains(ignoreLt, path)) {
                log.warn(">>>>>>>>>> ignore uri: [{}]", path);
                //next filter
                return chain.filter(exchange);
            }

            //step-2: auth
            String type = myConfig.getType();
            List<String> typeLt = StrUtil.splitTrim(type, ",");
            List<AuthService> authLt = AuthFactory.getAuthServiceLt(typeLt);
            if (CollectionUtil.isEmpty(authLt)) {
                log.info(">>>>>>>>>> ");
                return WriteUtils.write(exchange, JSONUtil.toJsonStr(Results.fail(801, "未知认证类型")));
            }
            //
            ServerHttpRequest request = WebUtils.getServerHttpRequest(exchange);
            ServerHttpRequest newRequest = request.mutate().build();
            ServerWebExchange newExchange = exchange.mutate().request(newRequest).build();
            //
            boolean authSucc = false;
            for (AuthService service : authLt) {
                authSucc = service.doAuth(newExchange, newRequest);
                if (authSucc) {
                    break;
                }
            }
            if (!authSucc) {
                return WriteUtils.write(exchange, JSONUtil.toJsonStr(Results.fail(802, "认证失败")));
            }

            //step-3: next filter
            Mono mono = chain.filter(exchange).then(Mono.fromRunnable(() -> {
                log.info("sadfadsf");
            }));

            log.info(">>>>>>>>>> auth GatewayFilter, order= {}", 1);
            return mono;
        }
    }

    /**
     * ==================================================
     * （★）自定义参数
     * ==================================================
     */
    @Data
    public static class MyConfig {
        private String type;
        private List<String> ignoreUris;
    }
}
